<template>
  <div ref="statsRef"></div>
  <div ref="containerRef" class="container"></div>
</template>

<script lang="ts" setup>
import {onMounted, ref, watch} from 'vue';
import {
  AxesHelper,
  Color,
  PerspectiveCamera,
  PlaneGeometry,
  Scene,
  WebGLRenderer,
  Mesh,
  BoxGeometry,
  SphereGeometry,
  SpotLight,
  MeshLambertMaterial,
  Fog,
  OrthographicCamera, Vector3
} from 'three';
import Stats from "stats.js"
// 导包交互页面
import * as dat from 'dat.gui'

/**
 * 获取页面的节点
 */
const statsRef = ref<HTMLDivElement>();
const containerRef = ref<HTMLDivElement>();
// 相机节点
const cameraRef = ref<PerspectiveCamera | OrthographicCamera>();
/**
 * 性能统计
 */
const stats = new Stats()
stats.showPanel(0)   // 就是不写，这个框体也会默认显示
// 创建一个场景
const scene = new Scene();


const renderer = new WebGLRenderer();

renderer.setClearColor(new Color(0xeeeeee));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true

/**
 * 光源设置
 */
const spotLight = new SpotLight(0xffffff,10000)
spotLight.position.set(-40, 30, -30);
spotLight.castShadow = true
scene.add(spotLight)

/**
 * 引入 x,y,z 线
 */
const axes = new AxesHelper(20);
scene.add(axes);

/**
 * 引入地板
 */
const planeGeometry = new PlaneGeometry(60, 40);
const meshBasicMaterial = new MeshLambertMaterial({color: 0xffffff});
const plane = new Mesh(planeGeometry, meshBasicMaterial);

plane.receiveShadow = true;
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0;
scene.add(plane);


/**
 * 引入正方体
 */
const cubeGeometry = new BoxGeometry(4, 4, 4);
const cubeMaterial = new MeshLambertMaterial({
  color: 0xff0000,
  wireframe: false,
});

const cube = new Mesh(cubeGeometry, cubeMaterial);
cube.castShadow=true
cube.position.set(2, 3, 2);
scene.add(cube);

/**
 * 在底面添加网格
 */
for(let j = 0; j < planeGeometry.parameters.height / 2; j++){
  for(let i = 0; i < planeGeometry.parameters.width / 2; i++){
    const cube = new Mesh(cubeGeometry, cubeMaterial);

    cube.castShadow = true;
    cube.position.z = -(planeGeometry.parameters.height / 2) + 2 + j * 5;
    cube.position.x = -(planeGeometry.parameters.width / 2) + 2 + i * 5;
    cube.position.y = 0;
    scene.add(cube);
  }
}


/**
 * 引入球体
 */
const sphereGeometry = new SphereGeometry(4);
const sphereMaterial = new MeshLambertMaterial({
  color: 0x7777ff,
  wireframe: false,
});

const sphere = new Mesh(sphereGeometry, sphereMaterial);
sphere.castShadow = true;
sphere.position.x = 20;
sphere.position.y = 4;
sphere.position.z = 2;
scene.add(sphere);


/**
 * 导入交互框
 */
const controlRef = ref({
  rotationSpeed: 0.02,
  bouncingSpeed: 0.03,
  numberOfObjects: 0,
  scaleX: 1,
  scaleY: 1,
  scaleZ: 1,
  positionX: 1,
  positionY: 1,
  positionZ: 1,
  translateX: 0,
  translateY: 0,
  translateZ: 0,
  obj: {
    x: 0,
    y: 0,
    z: 0,
  },
  camera: 'Perspective',
  addCube: function (){
    // 添加cube
    const cubeGeometry = new BoxGeometry(4, 4, 4);
    const cube = new Mesh(cubeGeometry, cubeMaterial);

    cube.name = 'cube-' + scene.children.length;
    cube.castShadow = true;
    cube.position.x = -30 + Math.round(Math.random() * 60);
    cube.position.y = Math.round(Math.random() * 5);
    cube.position.z = -20 + Math.round(Math.random() * 40);
    scene.add(cube);
    // 统计场景中的对象
    this.numberOfObjects = scene.children.length
  },
  remove: function(){
    const allChildren = scene.children;
    const lastObject = allChildren[allChildren.length - 1];

    if(lastObject instanceof Mesh && lastObject.name.startsWith('cube')){
      //mesh 网格模型，且名称以 cube 开头，新添加的立方体
      scene.remove(lastObject);
    }

    this.numberOfObjects = scene.children.length;
  },
  addFog: function (){
    scene.fog = new Fog(0xffffff, 0.015, 100);
    this.numberOfObjects = scene.children.length;
  },
  removeFog: function(){
    scene.fog = null;
    this.numberOfObjects = scene.children.length;
  },
  toggleMaterial: function () {
    if (!scene.overrideMaterial) {
      scene.overrideMaterial = new MeshLambertMaterial({
        color: 0xffffff,
      });
    }else {
      scene.overrideMaterial = null;
    }
    this.numberOfObjects = scene.children.length;
  },
  translate: function(){
    this.obj.x = this.translateX;
    this.obj.y = this.translateY;
    this.obj.z = this.translateZ;
  },
  switchCamera: function(){
    if(this.camera === 'Perspective'){
      //当前是透视相机
      this.camera = 'Orthographic';
    }else{
      //当前是正交相机
      this.camera = 'Perspective';
    }
  },
})
if (document.querySelectorAll(".dg.ac>.dg.main.a").length === 0){
  window.gui = new dat.GUI();
  window.gui.add(controlRef.value, 'rotationSpeed', 0, 0.5);
  window.gui.add(controlRef.value, 'bouncingSpeed', 0, 0.5);
  window.gui.add(controlRef.value, 'numberOfObjects').listen();
  window.gui.add(controlRef.value, 'addCube');
  window.gui.add(controlRef.value, 'remove');
  window.gui.add(controlRef.value, 'addFog');
  window.gui.add(controlRef.value, 'removeFog');
  window.gui.add(controlRef.value, 'toggleMaterial');
  window.gui.add(controlRef.value, 'switchCamera');
  window.gui.add(controlRef.value, 'camera').listen();

  // 添加x分组
  const scaleFolder = window.gui.addFolder('scale');
  scaleFolder.add(controlRef.value, 'scaleX', 0, 5);
  scaleFolder.add(controlRef.value, 'scaleY', 0, 5);
  scaleFolder.add(controlRef.value, 'scaleZ', 0, 5);
  const positionFolder = window.gui.addFolder('position');
  positionFolder.add(controlRef.value, 'positionX', -5, 5);
  positionFolder.add(controlRef.value, 'positionY', -5, 5);
  positionFolder.add(controlRef.value, 'positionZ', -5, 5);
  const translateFolder = window.gui.addFolder('translate');
  translateFolder.add(controlRef.value, 'translateX', -5, 5);
  translateFolder.add(controlRef.value, 'translateY', -5, 5);
  translateFolder.add(controlRef.value, 'translateZ', -5, 5);
  translateFolder.add(controlRef.value, 'translate');
}
// 添加监控 xyz轴的值修改
watch(
    () => controlRef.value.scaleX,
    (n) => {
      cube.scale.setX(n);
    }
);

watch(
    () => controlRef.value.scaleY,
    (n) => {
      cube.scale.setY(n);
    }
);

watch(
    () => controlRef.value.scaleZ,
    (n) => {
      cube.scale.setZ(n);
    }
);
watch(
    () => controlRef.value.positionX,
    (n) => {
      cube.position.setX(n);
    }
);

watch(
    () => controlRef.value.positionY,
    (n) => {
      cube.position.setY(n);
    }
);

watch(
    () => controlRef.value.positionZ,
    (n) => {
      cube.position.setZ(n);
    }
);

watch(
    () => controlRef.value.obj,
    (n) => {
      console.log('obj:');
      console.log(n);
      console.log('n.x:');
      console.log(n.x);
      cube.translateX(n.x);
      cube.translateY(n.y);
      cube.translateZ(n.z);
    },
    {
      deep: true,
    }
);
// 切换相机
watch(
    () => controlRef.value.camera,
    (n) => {
      if(n === 'Orthographic'){
        //改为正交相机
        cameraRef.value = new OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
        cameraRef.value.position.set(-90, 40, 130);
        cameraRef.value.lookAt(scene.position);
      }else{
        //改为透视相机
        cameraRef.value = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        cameraRef.value.position.set(-90, 40, 130);
        cameraRef.value.lookAt(scene.position);
      }
    }
);
/**
 * 目标对象位置
 */
const lookAtGeom = new SphereGeometry(4);
const lookAtMesh = new Mesh(lookAtGeom, new MeshLambertMaterial({
  color: 0x00ff00,
}));

scene.add(lookAtMesh);
/**
 * 添加动作
 */
let step = 0;
let stepCamera = 0;
function renderScene() {
  // 统计性能
  stats.update()
  if(cameraRef.value){
    //存在相机
    stepCamera += 0.02;

    const x = 10 + 100 * Math.sin(stepCamera);
    // const x = 10 + 100 * Math.cos(stepCamera);
    const v3 = new Vector3(x, 4, 0);
    lookAtMesh.position.copy(v3);
    // cameraRef.value.lookAt(x, 4, 0);
    cameraRef.value.lookAt(v3);
  }
  // 递归调用
  scene.traverse((e) => {
    if(e.name.startsWith('cube')){
      //名称以 cube 开头，新添加的立方体
      e.rotation.x += controlRef.value.rotationSpeed;
      e.rotation.y += controlRef.value.rotationSpeed;
      e.rotation.z += controlRef.value.rotationSpeed;
    }
  });
  cube.rotation.x += controlRef.value.rotationSpeed;
  cube.rotation.y += controlRef.value.rotationSpeed;
  cube.rotation.z += controlRef.value.rotationSpeed;

  //改变长宽
  // cube.scale.x += 0.01;

  step += controlRef.value.bouncingSpeed;
  sphere.position.x = 20 + 10 * Math.cos(step);
  sphere.position.y = 2 + 10 * Math.abs(Math.sin(step));

  requestAnimationFrame(renderScene)
  if(cameraRef.value){
    //存在相机
    renderer.render(scene, cameraRef.value);
  }
}
renderScene()

// 当页面大小发生变化后触发
window.addEventListener('resize', () => {
  if(cameraRef.value instanceof PerspectiveCamera){
    //透视相机
    cameraRef.value.aspect = window.innerWidth / window.innerHeight;
  }

  cameraRef.value!.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}, false);

// 加载页面内容
onMounted(() => {
  // 创建相机
  cameraRef.value = new PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,10000)
  cameraRef.value.position.set(-90, 40, 130);
  cameraRef.value.lookAt(scene.position);
  // 开机渲染
  statsRef.value?.append(stats.dom)
  containerRef.value?.appendChild(renderer.domElement);
  renderer.render(scene, cameraRef.value);
});
</script>

<style scoped>
</style>
